diff --git a/include/asterisk/bridge_basic.h b/include/asterisk/bridge_basic.h
index 4db1429469c2c80513e6dad3be9ed5a6e6201149..d048762353e2cf2864fab42cc5829e5b4ff418e7 100644
--- a/include/asterisk/bridge_basic.h
+++ b/include/asterisk/bridge_basic.h
@@ -88,6 +88,22 @@ struct ast_flags *ast_bridge_features_ds_get(struct ast_channel *chan);
  */
 int ast_bridge_features_ds_set(struct ast_channel *chan, struct ast_flags *flags);
 
+/*!
+ * \brief Append basic bridge DTMF feature flags on the channel.
+ * \since 12.0.0
+ *
+ * \param chan Channel to append DTMF features datastore.
+ * \param flags Builtin DTMF feature flags. (ast_bridge_config flags)
+ *
+ * \note The channel must be locked before calling this function.
+ * \note This function differs from ast_bridge_features_ds_set only in that it won't
+ *       remove features already set on the channel.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int ast_bridge_features_ds_append(struct ast_channel *chan, struct ast_flags *flags);
+
 /*!
  * \brief Setup DTMF feature hooks using the channel features datastore property.
  * \since 12.0.0
diff --git a/main/bridge_basic.c b/main/bridge_basic.c
index 10c4efb575b39ac5f3d1e1baa7ab8e5e5e2edce8..35782de285eff3f6b20b361dd115b4ce4a6b85bc 100644
--- a/main/bridge_basic.c
+++ b/main/bridge_basic.c
@@ -220,7 +220,7 @@ int ast_bridge_features_ds_get_string(struct ast_channel *chan, char *buffer, si
 	return dtmf_features_flags_to_string(&held_copy, buffer, buf_size);
 }
 
-int ast_bridge_features_ds_set(struct ast_channel *chan, struct ast_flags *flags)
+static int bridge_features_ds_set_full(struct ast_channel *chan, struct ast_flags *flags, int replace)
 {
 	struct ast_datastore *datastore;
 	struct ast_flags *ds_flags;
@@ -228,7 +228,12 @@ int ast_bridge_features_ds_set(struct ast_channel *chan, struct ast_flags *flags
 	datastore = ast_channel_datastore_find(chan, &dtmf_features_info, NULL);
 	if (datastore) {
 		ds_flags = datastore->data;
-		*ds_flags = *flags;
+		if (replace) {
+			*ds_flags = *flags;
+		} else {
+			flags->flags = flags->flags | ds_flags->flags;
+			*ds_flags = *flags;
+		}
 		return 0;
 	}
 
@@ -249,6 +254,16 @@ int ast_bridge_features_ds_set(struct ast_channel *chan, struct ast_flags *flags
 	return 0;
 }
 
+int ast_bridge_features_ds_set(struct ast_channel *chan, struct ast_flags *flags)
+{
+	return bridge_features_ds_set_full(chan, flags, 1);
+}
+
+int ast_bridge_features_ds_append(struct ast_channel *chan, struct ast_flags *flags)
+{
+	return bridge_features_ds_set_full(chan, flags, 0);
+}
+
 struct ast_flags *ast_bridge_features_ds_get(struct ast_channel *chan)
 {
 	struct ast_datastore *datastore;
diff --git a/main/features.c b/main/features.c
index 043ed591f58e2efce4ef394a31d851b2affb33f9..e2d668426ae681a97d36240fd0599d0b61296e0a 100644
--- a/main/features.c
+++ b/main/features.c
@@ -953,10 +953,10 @@ static int pre_bridge_setup(struct ast_channel *chan, struct ast_channel *peer,
 
 	res = 0;
 	ast_channel_lock(chan);
-	res |= ast_bridge_features_ds_set(chan, &config->features_caller);
+	res |= ast_bridge_features_ds_append(chan, &config->features_caller);
 	ast_channel_unlock(chan);
 	ast_channel_lock(peer);
-	res |= ast_bridge_features_ds_set(peer, &config->features_callee);
+	res |= ast_bridge_features_ds_append(peer, &config->features_callee);
 	ast_channel_unlock(peer);
 
 	if (res) {