diff --git a/daemon/call.c b/daemon/call.c
index 405754518..285f9ca8c 100644
--- a/daemon/call.c
+++ b/daemon/call.c
@@ -2998,7 +2998,7 @@ static void __unsubscribe_from_all(struct call_monologue *ml) {
 	}
 }
 void __add_subscription(struct call_monologue *which, struct call_monologue *to, bool offer_answer,
-		unsigned int offset, bool rtcp_only, bool egress)
+		unsigned int offset, bool rtcp_only, bool egress, const struct sink_attrs *attrs)
 {
 	if (g_hash_table_lookup(which->subscriptions_ht, to)) {
 		ilog(LOG_DEBUG, "Tag '" STR_FORMAT_M "' is already subscribed to '" STR_FORMAT_M "'",
@@ -3015,6 +3015,12 @@ void __add_subscription(struct call_monologue *which, struct call_monologue *to,
 	to_rev_cs->monologue = which;
 	which_cs->media_offset = offset;
 	to_rev_cs->media_offset = offset;
+	// preserve attributes if they were present previously
+	if (attrs) {
+		which_cs->attrs = *attrs;
+		to_rev_cs->attrs = *attrs;
+	}
+	// override some attributes explicitly
 	which_cs->attrs.rtcp_only = rtcp_only ? 1 : 0;
 	to_rev_cs->attrs.rtcp_only = rtcp_only ? 1 : 0;
 	// keep offer-answer subscriptions first in the list
@@ -3038,10 +3044,26 @@ void __add_subscription(struct call_monologue *which, struct call_monologue *to,
 	g_hash_table_insert(to->subscribers_ht, which, which_cs->link);
 }
 static void __subscribe_offer_answer_both_ways(struct call_monologue *a, struct call_monologue *b) {
+	// retrieve previous subscriptions to retain attributes
+	struct call_subscription *a_cs = call_get_call_subscription(a->subscriptions_ht, b);
+	struct call_subscription *b_cs = call_get_call_subscription(b->subscriptions_ht, a);
+	// copy out attributes
+	struct sink_attrs a_attrs = {0,}, *a_attrs_p = NULL;
+	struct sink_attrs b_attrs = {0,}, *b_attrs_p = NULL;
+	if (a_cs) {
+		a_attrs = a_cs->attrs;
+		a_attrs_p = &a_attrs;
+	}
+	if (b_cs) {
+		b_attrs = b_cs->attrs;
+		b_attrs_p = &b_attrs;
+	}
+	// delete existing subscriptions
 	__unsubscribe_all_offer_answer_subscribers(a);
 	__unsubscribe_all_offer_answer_subscribers(b);
-	__add_subscription(a, b, true, 0, false, false);
-	__add_subscription(b, a, true, 0, false, false);
+	// (re)create, preserving existing attributes if there were any
+	__add_subscription(a, b, true, 0, false, false, a_attrs_p);
+	__add_subscription(b, a, true, 0, false, false, b_attrs_p);
 }
 
 
@@ -3178,9 +3200,9 @@ static int monologue_subscribe_request1(struct call_monologue *src_ml, struct ca
 			return -1;
 	}
 
-	__add_subscription(dst_ml, src_ml, false, idx_diff, false, flags->egress ? true : false);
+	__add_subscription(dst_ml, src_ml, false, idx_diff, false, flags->egress ? true : false, NULL);
 	if (flags->rtcp_mirror)
-		__add_subscription(src_ml, dst_ml, false, rev_idx_diff, true, flags->egress ? true : false);
+		__add_subscription(src_ml, dst_ml, false, rev_idx_diff, true, flags->egress ? true : false, NULL);
 
 	__update_init_subscribers(src_ml, NULL, NULL, flags->opmode);
 	__update_init_subscribers(dst_ml, NULL, NULL, flags->opmode);
diff --git a/daemon/redis.c b/daemon/redis.c
index 7a5f76a21..22e37048c 100644
--- a/daemon/redis.c
+++ b/daemon/redis.c
@@ -1658,7 +1658,7 @@ static int rbl_subs_cb(str *s, GQueue *q, struct redis_list *list, void *ptr) {
 	if (!other_ml)
 		return -1;
 
-	__add_subscription(ml, other_ml, offer_answer, media_offset, rtcp_only, egress);
+	__add_subscription(ml, other_ml, offer_answer, media_offset, rtcp_only, egress, NULL);
 
 	return 0;
 }
@@ -1683,7 +1683,7 @@ static int json_link_tags(struct call *c, struct redis_list *tags, struct redis_
 				other_ml = l->data;
 				if (!other_ml)
 					return -1;
-				__add_subscription(ml, other_ml, true, 0, false, false);
+				__add_subscription(ml, other_ml, true, 0, false, false, NULL);
 			}
 			g_queue_clear(&q);
 
@@ -1693,7 +1693,7 @@ static int json_link_tags(struct call *c, struct redis_list *tags, struct redis_
 				other_ml = l->data;
 				if (!other_ml)
 					return -1;
-				__add_subscription(ml, other_ml, false, 0, false, false);
+				__add_subscription(ml, other_ml, false, 0, false, false, NULL);
 			}
 			g_queue_clear(&q);
 		}
@@ -1702,7 +1702,7 @@ static int json_link_tags(struct call *c, struct redis_list *tags, struct redis_
 		if (!ml->subscriptions.length) {
 			other_ml = redis_list_get_ptr(tags, &tags->rh[i], "active");
 			if (other_ml)
-				__add_subscription(ml, other_ml, true, 0, false, false);
+				__add_subscription(ml, other_ml, true, 0, false, false, NULL);
 		}
 
 		if (json_build_list(&q, c, "other_tags", i, tags, root_reader))
diff --git a/include/call.h b/include/call.h
index e50f28cee..19027b87b 100644
--- a/include/call.h
+++ b/include/call.h
@@ -647,7 +647,7 @@ void __monologue_tag(struct call_monologue *ml, const str *tag);
 void __monologue_viabranch(struct call_monologue *ml, const str *viabranch);
 struct packet_stream *__packet_stream_new(struct call *call);
 void __add_subscription(struct call_monologue *ml, struct call_monologue *other, bool offer_answer,
-		unsigned int media_offset, bool rtcp_only, bool egress);
+		unsigned int media_offset, bool rtcp_only, bool egress, const struct sink_attrs *);
 struct call_subscription *call_get_call_subscription(GHashTable *ht, struct call_monologue *ml);
 void free_sink_handler(void *);
 void __add_sink_handler(GQueue *, struct packet_stream *, const struct sink_attrs *);