diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index e5f792f1f413a5c57895298369ad70bb830bccc2..4170a8af4566c9b01f30f94855dd41c11ed16f57 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -884,6 +884,10 @@ enum {
 	 * world
 	 */
 	AST_CHAN_TP_INTERNAL = (1 << 2),
+	/*!
+	 * \brief Channels with this particular technology support multiple simultaneous streams
+	 */
+	AST_CHAN_TP_MULTISTREAM = (1 << 3),
 };
 
 /*! \brief ast_channel flags */
@@ -4734,4 +4738,34 @@ enum ast_channel_error ast_channel_errno(void);
  */
 int ast_channel_get_intercept_mode(void);
 
+/*!
+ * \brief Retrieve the topology of streams on a channel
+ *
+ * \param chan The channel to get the stream topology of
+ *
+ * \pre chan is locked
+ *
+ * \retval non-NULL success
+ * \retval NULL failure
+ */
+struct ast_stream_topology *ast_channel_get_stream_topology(
+	const struct ast_channel *chan);
+
+/*!
+ * \brief Set the topology of streams on a channel
+ *
+ * \param chan The channel to set the stream topology on
+ * \param topology The stream topology to set
+ *
+ * \pre chan is locked
+ *
+ * \note If topology is NULL a new empty topology will be created
+ * and returned.
+ *
+ * \retval non-NULL Success
+ * \retval NULL failure
+ */
+struct ast_stream_topology *ast_channel_set_stream_topology(
+	struct ast_channel *chan, struct ast_stream_topology *topology);
+
 #endif /* _ASTERISK_CHANNEL_H */
diff --git a/include/asterisk/channel_internal.h b/include/asterisk/channel_internal.h
index 2316e2f24c9e128860ecf15071e07b895abafaee..3de2b14aa1ca4b0c97466260925db140dd1f4a41 100644
--- a/include/asterisk/channel_internal.h
+++ b/include/asterisk/channel_internal.h
@@ -27,3 +27,7 @@ int ast_channel_internal_setup_topics(struct ast_channel *chan);
 
 void ast_channel_internal_errno_set(enum ast_channel_error error);
 enum ast_channel_error ast_channel_internal_errno(void);
+void ast_channel_internal_set_stream_topology(struct ast_channel *chan,
+	struct ast_stream_topology *topology);
+void ast_channel_internal_swap_stream_topology(struct ast_channel *chan1,
+	struct ast_channel *chan2);
diff --git a/include/asterisk/stream.h b/include/asterisk/stream.h
index cffe6ea4cb138b56617970f2419c10386df38239..9fb466013528ac1855a2a26dbb50a61798454a63 100644
--- a/include/asterisk/stream.h
+++ b/include/asterisk/stream.h
@@ -316,4 +316,19 @@ int ast_stream_topology_set_stream(struct ast_stream_topology *topology,
 struct ast_stream_topology *ast_stream_topology_create_from_format_cap(
 	struct ast_format_cap *cap);
 
+/*!
+ * \brief Gets the first stream of a specific type from the topology
+ *
+ * \param topology The topology of streams
+ * \param type The media type
+ *
+ * \retval non-NULL success
+ * \retval NULL failure
+ *
+ * \since 15
+ */
+struct ast_stream *ast_stream_topology_get_first_stream_by_type(
+	const struct ast_stream_topology *topology,
+	enum ast_media_type type);
+
 #endif /* _AST_STREAM_H */
diff --git a/main/channel.c b/main/channel.c
index 54db473515d6428cb0391937a81a17adcfed3730..c74e9475fb5856d84d4af7d1f5a4b712c1030cd2 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -73,6 +73,7 @@
 #include "asterisk/test.h"
 #include "asterisk/stasis_channels.h"
 #include "asterisk/max_forwards.h"
+#include "asterisk/stream.h"
 
 /*** DOCUMENTATION
  ***/
@@ -806,6 +807,7 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char
 	struct ast_timer *timer;
 	struct timeval now;
 	const struct ast_channel_tech *channel_tech;
+	struct ast_stream_topology *topology;
 
 	/* If shutting down, don't allocate any new channels */
 	if (ast_shutting_down()) {
@@ -895,6 +897,11 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char
 		return ast_channel_unref(tmp);
 	}
 
+	if (!(topology = ast_stream_topology_create())) {
+		return ast_channel_unref(tmp);
+	}
+	ast_channel_internal_set_stream_topology(tmp, topology);
+
 	/* Always watch the alertpipe */
 	ast_channel_set_fd(tmp, AST_ALERT_FD, ast_channel_internal_alert_readfd(tmp));
 	/* And timing pipe */
@@ -7083,6 +7090,8 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann
 			ast_channel_tech(clonechan)->type, ast_channel_name(clonechan));
 	}
 
+	ast_channel_internal_swap_stream_topology(original, clonechan);
+
 	/*
 	 * Now, at this point, the "clone" channel is totally F'd up.
 	 * We mark it as a zombie so nothing tries to touch it.
diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c
index a0cbe8643780f7b01b33f8eb5bd2c44e4fc73c1a..235b99604b0ba76b66201998718119c8f1d01353 100644
--- a/main/channel_internal_api.c
+++ b/main/channel_internal_api.c
@@ -46,6 +46,7 @@
 #include "asterisk/stasis_channels.h"
 #include "asterisk/stasis_endpoints.h"
 #include "asterisk/stringfields.h"
+#include "asterisk/stream.h"
 #include "asterisk/test.h"
 
 /*!
@@ -221,6 +222,8 @@ struct ast_channel {
 	struct stasis_cp_single *topics;		/*!< Topic for all channel's events */
 	struct stasis_forward *endpoint_forward;	/*!< Subscription for event forwarding to endpoint's topic */
 	struct stasis_forward *endpoint_cache_forward; /*!< Subscription for cache updates to endpoint's topic */
+	struct ast_stream_topology *stream_topology; /*!< Stream topology */
+	struct ast_stream *default_streams[AST_MEDIA_TYPE_END]; /*!< Default streams indexed by media type */
 };
 
 /*! \brief The monotonically increasing integer counter for channel uniqueids */
@@ -825,10 +828,57 @@ struct ast_format_cap *ast_channel_nativeformats(const struct ast_channel *chan)
 {
 	return chan->nativeformats;
 }
-void ast_channel_nativeformats_set(struct ast_channel *chan, struct ast_format_cap *value)
+
+static void channel_set_default_streams(struct ast_channel *chan)
+{
+	enum ast_media_type type;
+
+	ast_assert(chan != NULL);
+
+	for (type = AST_MEDIA_TYPE_UNKNOWN; type < AST_MEDIA_TYPE_END; type++) {
+		if (chan->stream_topology) {
+			chan->default_streams[type] =
+				ast_stream_topology_get_first_stream_by_type(chan->stream_topology, type);
+		} else {
+			chan->default_streams[type] = NULL;
+		}
+	}
+}
+
+void ast_channel_internal_set_stream_topology(struct ast_channel *chan,
+	struct ast_stream_topology *topology)
+{
+	ast_stream_topology_destroy(chan->stream_topology);
+	chan->stream_topology = topology;
+	channel_set_default_streams(chan);
+}
+
+void ast_channel_nativeformats_set(struct ast_channel *chan,
+	struct ast_format_cap *value)
 {
+	ast_assert(chan != NULL);
+
 	ao2_replace(chan->nativeformats, value);
+
+	/* If chan->stream_topology is NULL, the channel is being destroyed
+	 * and topology is destroyed.
+	 */
+	if (!chan->stream_topology) {
+		return;
+	}
+
+	if (!chan->tech || !(chan->tech->properties & AST_CHAN_TP_MULTISTREAM) || !value) {
+		struct ast_stream_topology *new_topology;
+
+		if (!value) {
+			new_topology = ast_stream_topology_create();
+		} else {
+			new_topology = ast_stream_topology_create_from_format_cap(value);
+		}
+		ast_channel_internal_set_stream_topology(chan, new_topology);
+	}
 }
+
 struct ast_framehook_list *ast_channel_framehooks(const struct ast_channel *chan)
 {
 	return chan->framehooks;
@@ -1637,6 +1687,8 @@ void ast_channel_internal_cleanup(struct ast_channel *chan)
 
 	stasis_cp_single_unsubscribe(chan->topics);
 	chan->topics = NULL;
+
+	ast_channel_internal_set_stream_topology(chan, NULL);
 }
 
 void ast_channel_internal_finalize(struct ast_channel *chan)
@@ -1729,3 +1781,52 @@ enum ast_channel_error ast_channel_internal_errno(void)
 
 	return *error_code;
 }
+
+struct ast_stream_topology *ast_channel_get_stream_topology(
+	const struct ast_channel *chan)
+{
+	ast_assert(chan != NULL);
+
+	return chan->stream_topology;
+}
+
+struct ast_stream_topology *ast_channel_set_stream_topology(struct ast_channel *chan,
+	struct ast_stream_topology *topology)
+{
+	struct ast_stream_topology *new_topology;
+
+	ast_assert(chan != NULL);
+
+	/* A non-MULTISTREAM channel can't manipulate topology directly */
+	ast_assert(chan->tech != NULL && (chan->tech->properties & AST_CHAN_TP_MULTISTREAM));
+
+	/* Unless the channel is being destroyed, we always want a topology on
+	 * it even if its empty.
+	 */
+	if (!topology) {
+		new_topology = ast_stream_topology_create();
+	} else {
+		new_topology = topology;
+	}
+
+	if (new_topology) {
+		ast_channel_internal_set_stream_topology(chan, new_topology);
+	}
+
+	return new_topology;
+}
+
+void ast_channel_internal_swap_stream_topology(struct ast_channel *chan1,
+	struct ast_channel *chan2)
+{
+	struct ast_stream_topology *tmp_topology;
+
+	ast_assert(chan1 != NULL && chan2 != NULL);
+
+	tmp_topology = chan1->stream_topology;
+	chan1->stream_topology = chan2->stream_topology;
+	chan2->stream_topology = tmp_topology;
+
+	channel_set_default_streams(chan1);
+	channel_set_default_streams(chan2);
+}
diff --git a/main/stream.c b/main/stream.c
index 24844c4abeb85c5e7773e9a3bab0628bcab245db..5112c959360cf7170cb3105b2cc4d2e075abe246 100644
--- a/main/stream.c
+++ b/main/stream.c
@@ -337,3 +337,22 @@ struct ast_stream_topology *ast_stream_topology_create_from_format_cap(
 
 	return topology;
 }
+
+struct ast_stream *ast_stream_topology_get_first_stream_by_type(
+	const struct ast_stream_topology *topology,
+	enum ast_media_type type)
+{
+	int i;
+
+	ast_assert(topology != NULL);
+
+	for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) {
+		struct ast_stream *stream = AST_VECTOR_GET(&topology->streams, i);
+
+		if (stream->type == type) {
+			return stream;
+		}
+	}
+
+	return NULL;
+}
diff --git a/tests/test_voicemail_api.c b/tests/test_voicemail_api.c
index 802b6bf1b110eb5ffd3eab6f79b0963eb27c16ac..e46757263f331ece4a6d1ec3894766ea4d8311d8 100644
--- a/tests/test_voicemail_api.c
+++ b/tests/test_voicemail_api.c
@@ -825,12 +825,12 @@ static struct ast_channel *test_vm_api_create_mock_channel(void)
 	}
 
 	ast_channel_set_writeformat(mock_channel, ast_format_gsm);
-	native_formats = ast_channel_nativeformats(mock_channel);
-	ast_format_cap_append(native_formats, ast_channel_writeformat(mock_channel), 0);
 	ast_channel_set_rawwriteformat(mock_channel, ast_format_gsm);
 	ast_channel_set_readformat(mock_channel, ast_format_gsm);
 	ast_channel_set_rawreadformat(mock_channel, ast_format_gsm);
 	ast_channel_tech_set(mock_channel, &mock_channel_tech);
+	native_formats = ast_channel_nativeformats(mock_channel);
+	ast_format_cap_append(native_formats, ast_channel_writeformat(mock_channel), 0);
 
 	ast_channel_unlock(mock_channel);