diff --git a/daemon/codec.c b/daemon/codec.c
index 4b95614e6..2d86ad4a3 100644
--- a/daemon/codec.c
+++ b/daemon/codec.c
@@ -297,6 +297,7 @@ static codec_handler_func handler_func_playback;
 static codec_handler_func handler_func_inject_dtmf;
 static codec_handler_func handler_func_dtmf;
 static codec_handler_func handler_func_t38;
+static codec_handler_func handler_func_blackhole;
 
 static struct ssrc_entry *__ssrc_handler_transcode_new(void *p);
 static struct ssrc_entry *__ssrc_handler_decode_new(void *p);
@@ -347,6 +348,14 @@ static struct codec_handler codec_handler_stub_ssrc = {
 	.kernelize = true,
 	.passthrough = true,
 };
+static struct codec_handler codec_handler_stub_blackhole = {
+	.source_pt.payload_type = -1,
+	.dest_pt.payload_type = -1,
+	.handler_func = handler_func_blackhole,
+	.blackhole = true,
+	.kernelize = true,
+	.passthrough = false,
+};
 
 
 
@@ -369,6 +378,7 @@ static void __handler_shutdown(struct codec_handler *handler) {
 	handler->pcm_dtmf_detect = false;
 	handler->passthrough = false;
 	handler->payload_len = 0;
+	handler->blackhole = false;
 
 	codec_handler_free(&handler->dtmf_injector);
 
@@ -485,6 +495,10 @@ static void __handler_stats_entry(struct codec_handler *handler) {
 	__atomic_fetch_add(&stats_entry->num_transcoders, 1, __ATOMIC_RELAXED);
 }
 
+static int handler_func_blackhole(struct codec_handler *h, struct media_packet *mp) {
+	return 0;
+}
+
 static void __reset_sequencer(void *p, void *dummy) {
 	struct ssrc_entry_call *s = p;
 	if (s->sequencers)
@@ -506,7 +520,7 @@ static bool __make_transcoder_full(struct codec_handler *handler, rtp_payload_ty
 		goto reset;
 	if (!rtp_payload_type_eq_exact(dest, &handler->dest_pt))
 		goto reset;
-	if (handler->handler_func != handler_func_transcode)
+	if (handler->handler_func != handler_func_transcode && handler->handler_func != handler_func_blackhole)
 		goto reset;
 	if (handler->packet_decoded != packet_decoded)
 		goto reset;
@@ -1780,6 +1794,8 @@ struct codec_handler *codec_handler_get(struct call_media *m, int payload_type,
 out:
 	if (ret)
 		return ret;
+	if (MEDIA_ISSET(sink, SELECT_PT))
+		return &codec_handler_stub_blackhole;
 	if (sh && sh->attrs.transcoding)
 		return &codec_handler_stub_ssrc;
 #endif
diff --git a/daemon/media_socket.c b/daemon/media_socket.c
index 86d4061f1..0f362bec5 100644
--- a/daemon/media_socket.c
+++ b/daemon/media_socket.c
@@ -1657,6 +1657,8 @@ static const char *kernelize_target(kernelize_state *s, struct packet_stream *st
 			struct codec_handler *ch = codec_handler_get(media, rs->payload_type,
 					ksink->media, ksh);
 
+			if (ch->blackhole)
+				s->manipulate_pt = true;
 			if (ch->kernelize)
 				continue;
 
@@ -1744,6 +1746,8 @@ static const char *kernelize_one(kernelize_state *s,
 
 			if (ML_ISSET(media->monologue, BLOCK_SHORT) && ch->payload_len)
 				rpt->min_payload_len = ch->payload_len;
+
+			rpt->blackhole = ch->blackhole;
 		}
 
 	}
diff --git a/include/call.h b/include/call.h
index 83539dea2..a010e37e9 100644
--- a/include/call.h
+++ b/include/call.h
@@ -218,6 +218,7 @@ enum {
  * if not set, then inactive.
  */
 #define MEDIA_FLAG_REAL_SENDONLY		(1LL << 35)
+#define MEDIA_FLAG_SELECT_PT			(1LL << 36)
 
 /* struct call_monologue */
 #define ML_FLAG_REC_FORWARDING			(1LL << 16)
diff --git a/include/codec.h b/include/codec.h
index 28e212c20..c33b7a18c 100644
--- a/include/codec.h
+++ b/include/codec.h
@@ -58,6 +58,7 @@ struct codec_handler {
 	bool kernelize:1;
 	bool transcoder:1;
 	bool pcm_dtmf_detect:1;
+	bool blackhole:1;
 
 	size_t payload_len; // for short-packet blocking
 
diff --git a/kernel-module/xt_RTPENGINE.c b/kernel-module/xt_RTPENGINE.c
index e5b6a574c..da749e79e 100644
--- a/kernel-module/xt_RTPENGINE.c
+++ b/kernel-module/xt_RTPENGINE.c
@@ -1796,6 +1796,9 @@ static int proc_list_show(struct seq_file *f, void *v) {
 						g->target.pt_stats[j]->payload_type,
 						o->output.pt_output[j].replace_pattern_len,
 						o->output.pt_output[j].min_payload_len);
+			if (o->output.pt_output[j].blackhole)
+				seq_printf(f, "        RTP payload type %3u: blackhole\n",
+						g->target.pt_stats[j]->payload_type);
 		}
 
 		proc_list_crypto_print(f, &o->encrypt_rtp, &o->output.encrypt, "encryption");
@@ -6023,8 +6026,12 @@ static bool proxy_packet_output_rtXp(struct sk_buff *skb, struct rtpengine_outpu
 		return true;
 	}
 
-	// pattern rewriting
 	if (rtp_pt_idx >= 0) {
+		// blackhole?
+		if (o->output.pt_output[rtp_pt_idx].blackhole)
+			return false;
+
+		// pattern rewriting
 		if (o->output.pt_output[rtp_pt_idx].min_payload_len
 				&& rtp->payload_len < o->output.pt_output[rtp_pt_idx].min_payload_len)
 			return false;
diff --git a/kernel-module/xt_RTPENGINE.h b/kernel-module/xt_RTPENGINE.h
index bb6264e20..738ee426c 100644
--- a/kernel-module/xt_RTPENGINE.h
+++ b/kernel-module/xt_RTPENGINE.h
@@ -78,6 +78,7 @@ struct rtpengine_pt_output {
 	unsigned int min_payload_len;
 	char replace_pattern[16];
 	unsigned char replace_pattern_len;
+	unsigned int blackhole:1;
 };
 
 struct rtpengine_target_info {