diff --git a/include/asterisk/bridge_channel_internal.h b/include/asterisk/bridge_channel_internal.h
index e3fb73d7e13e0a76fc45dfb70e20fb79cb3ad39b..7f7d5a88b14583204331175cf690e3dcaccf5c8c 100644
--- a/include/asterisk/bridge_channel_internal.h
+++ b/include/asterisk/bridge_channel_internal.h
@@ -84,7 +84,7 @@ struct ast_bridge_channel *bridge_channel_internal_alloc(struct ast_bridge *brid
 
 /*!
  * \internal
- * \brief Clear owed events by the channel to the original bridge.
+ * \brief Settle owed events by the channel to the original bridge.
  * \since 12.0.0
  *
  * \param orig_bridge Original bridge the channel was in before leaving.
@@ -116,6 +116,27 @@ void bridge_channel_settle_owed_events(struct ast_bridge *orig_bridge, struct as
  */
 int bridge_channel_internal_push(struct ast_bridge_channel *bridge_channel);
 
+/*!
+ * \internal
+ * \brief Push the bridge channel into its specified bridge.
+ * \since 13.8.0
+ *
+ * \param bridge_channel Channel to push.
+ * \param optimized non-zero if the push with swap is for an optimization.
+ *
+ * \note A ref is not held by bridge_channel->swap when calling because the
+ * push with swap happens immediately.
+ *
+ * \note On entry, bridge_channel->bridge is already locked.
+ *
+ * \retval 0 on success.
+ * \retval -1 on failure.  The channel did not get pushed.
+ *
+ * \note On failure the caller must call
+ * ast_bridge_features_remove(bridge_channel->features, AST_BRIDGE_HOOK_REMOVE_ON_PULL);
+ */
+int bridge_channel_internal_push_full(struct ast_bridge_channel *bridge_channel, int optimized);
+
 /*!
  * \internal
  * \brief Pull the bridge channel out of its current bridge.
diff --git a/main/bridge.c b/main/bridge.c
index 7451a163c7e0a442db055bc80fd6d33f61b6e6d8..77865757ea3b1505e0557dbe19a2bdaebfbd3c12 100644
--- a/main/bridge.c
+++ b/main/bridge.c
@@ -2185,7 +2185,7 @@ int bridge_do_move(struct ast_bridge *dst_bridge, struct ast_bridge_channel *bri
 
 	bridge_channel_moving(bridge_channel, orig_bridge, dst_bridge);
 
-	if (bridge_channel_internal_push(bridge_channel)) {
+	if (bridge_channel_internal_push_full(bridge_channel, optimized)) {
 		/* Try to put the channel back into the original bridge. */
 		ast_bridge_features_remove(bridge_channel->features,
 			AST_BRIDGE_HOOK_REMOVE_ON_PULL);
@@ -2198,7 +2198,6 @@ int bridge_do_move(struct ast_bridge *dst_bridge, struct ast_bridge_channel *bri
 					AST_BRIDGE_HOOK_REMOVE_ON_PULL);
 				ast_bridge_channel_leave_bridge(bridge_channel,
 					BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, bridge_channel->bridge->cause);
-				bridge_channel_settle_owed_events(orig_bridge, bridge_channel);
 			}
 		} else {
 			ast_bridge_channel_leave_bridge(bridge_channel,
@@ -2206,7 +2205,7 @@ int bridge_do_move(struct ast_bridge *dst_bridge, struct ast_bridge_channel *bri
 			bridge_channel_settle_owed_events(orig_bridge, bridge_channel);
 		}
 		res = -1;
-	} else {
+	} else if (!optimized) {
 		bridge_channel_settle_owed_events(orig_bridge, bridge_channel);
 	}
 
diff --git a/main/bridge_channel.c b/main/bridge_channel.c
index f3483e4403fa128afdbe6d423e72b465d24923d7..3f141452e500810c308fa79da43749d106bc374b 100644
--- a/main/bridge_channel.c
+++ b/main/bridge_channel.c
@@ -675,6 +675,22 @@ static int bridge_channel_write_frame(struct ast_bridge_channel *bridge_channel,
 	return 0;
 }
 
+/*!
+ * \internal
+ * \brief Cancel owed events by the channel to the bridge.
+ * \since 13.8.0
+ *
+ * \param bridge_channel Channel that owes events to the bridge.
+ *
+ * \note On entry, the bridge_channel->bridge is already locked.
+ *
+ * \return Nothing
+ */
+static void bridge_channel_cancel_owed_events(struct ast_bridge_channel *bridge_channel)
+{
+	bridge_channel->owed.dtmf_digit = '\0';
+}
+
 void bridge_channel_settle_owed_events(struct ast_bridge *orig_bridge, struct ast_bridge_channel *bridge_channel)
 {
 	if (bridge_channel->owed.dtmf_digit) {
@@ -2037,7 +2053,7 @@ void bridge_channel_internal_pull(struct ast_bridge_channel *bridge_channel)
 	ast_bridge_publish_leave(bridge, bridge_channel->chan);
 }
 
-int bridge_channel_internal_push(struct ast_bridge_channel *bridge_channel)
+int bridge_channel_internal_push_full(struct ast_bridge_channel *bridge_channel, int optimized)
 {
 	struct ast_bridge *bridge = bridge_channel->bridge;
 	struct ast_bridge_channel *swap;
@@ -2073,6 +2089,9 @@ int bridge_channel_internal_push(struct ast_bridge_channel *bridge_channel)
 		/* This flag is cleared so the act of this channel leaving does not cause it to dissolve if need be */
 		ast_clear_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_DISSOLVE_EMPTY);
 
+		if (optimized) {
+			bridge_channel_cancel_owed_events(swap);
+		}
 		ast_bridge_channel_leave_bridge(swap, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, 0);
 		bridge_channel_internal_pull(swap);
 
@@ -2112,6 +2131,11 @@ int bridge_channel_internal_push(struct ast_bridge_channel *bridge_channel)
 	return 0;
 }
 
+int bridge_channel_internal_push(struct ast_bridge_channel *bridge_channel)
+{
+	return bridge_channel_internal_push_full(bridge_channel, 0);
+}
+
 /*!
  * \internal
  * \brief Handle bridge channel control frame action.