diff --git a/subprojects/gst-plugins-base/gst-libs/gst/gl/gstglupload.c b/subprojects/gst-plugins-base/gst-libs/gst/gl/gstglupload.c
index 246e6c6168..fd20c53b65 100644
--- a/subprojects/gst-plugins-base/gst-libs/gst/gl/gstglupload.c
+++ b/subprojects/gst-plugins-base/gst-libs/gst/gl/gstglupload.c
@@ -315,6 +315,85 @@ struct _UploadMethod
   void (*free) (gpointer impl);
 } _UploadMethod;
 
+struct PassthroughUpload
+{
+  GstGLUpload *upload;
+};
+
+static gpointer
+_passthrough_upload_new (GstGLUpload * upload)
+{
+  struct PassthroughUpload *passthrough = g_new0 (struct PassthroughUpload, 1);
+
+  passthrough->upload = upload;
+
+  return passthrough;
+}
+
+static GstStaticCaps _passthrough_upload_caps =
+GST_STATIC_CAPS (GST_VIDEO_DMA_DRM_CAPS_MAKE);
+
+static GstCaps *
+_passthrough_upload_transform_caps (gpointer impl, GstGLContext * context,
+    GstPadDirection direction, GstCaps * caps)
+{
+  GstCaps *passthrough_caps = gst_static_caps_get (&_passthrough_upload_caps);
+  GstCaps *out_caps;
+
+  out_caps = gst_caps_intersect_full (caps, passthrough_caps,
+      GST_CAPS_INTERSECT_FIRST);
+  gst_caps_unref (passthrough_caps);
+
+  return out_caps;
+}
+
+static gboolean
+_passthrough_upload_accept (gpointer impl, GstBuffer * buffer,
+    GstCaps * in_caps, GstCaps * out_caps)
+{
+  GstCaps *caps;
+  gboolean res;
+
+  caps = gst_caps_intersect (in_caps, out_caps);
+  res = !gst_caps_is_empty (caps);
+  gst_caps_unref (caps);
+
+  return res;
+}
+
+static void
+_passthrough_upload_propose_allocation (gpointer impl, GstQuery * decide_query,
+    GstQuery * query)
+{
+}
+
+static GstGLUploadReturn
+_passthrough_upload_perform (gpointer impl, GstBuffer * buffer,
+    GstBuffer ** outbuf)
+{
+  *outbuf = gst_buffer_ref (buffer);
+
+  return GST_GL_UPLOAD_DONE;
+}
+
+static void
+_passthrough_upload_free (gpointer impl)
+{
+  g_free (impl);
+}
+
+static const UploadMethod _passthrough_upload = {
+  "Dmabuf Passthrough",
+  0,
+  &_passthrough_upload_caps,
+  &_passthrough_upload_new,
+  &_passthrough_upload_transform_caps,
+  &_passthrough_upload_accept,
+  &_passthrough_upload_propose_allocation,
+  &_passthrough_upload_perform,
+  &_passthrough_upload_free
+};
+
 struct GLMemoryUpload
 {
   GstGLUpload *upload;
@@ -3115,7 +3194,9 @@ static const UploadMethod _nvmm_upload = {
 
 #endif /* HAVE_NVMM */
 
-static const UploadMethod *upload_methods[] = { &_gl_memory_upload,
+static const UploadMethod *upload_methods[] = {
+  &_passthrough_upload,
+  &_gl_memory_upload,
 #if GST_GL_HAVE_DMABUF
   &_direct_dma_buf_upload,
   &_direct_dma_buf_external_upload,
diff --git a/subprojects/gst-plugins-base/tests/check/libs/gstglupload.c b/subprojects/gst-plugins-base/tests/check/libs/gstglupload.c
index eff2f18ba5..523f05a561 100644
--- a/subprojects/gst-plugins-base/tests/check/libs/gstglupload.c
+++ b/subprojects/gst-plugins-base/tests/check/libs/gstglupload.c
@@ -70,6 +70,18 @@ static gchar rgba_data[] =
   RED, GREEN, BLUE, RED, GREEN, BLUE, RED, GREEN, BLUE, RED
 };
 
+#ifndef GST_CAPS_FEATURE_MEMORY_DMABUF
+#define GST_CAPS_FEATURE_MEMORY_DMABUF "memory:DMABuf"
+#endif
+
+static GstVideoFormat test_passthrough_formats[] = {
+  GST_VIDEO_FORMAT_DMA_DRM,
+};
+
+static const gchar *test_passthrough_features[] = {
+  GST_CAPS_FEATURE_MEMORY_DMABUF,
+};
+
 static void
 setup (void)
 {
@@ -417,6 +429,64 @@ GST_START_TEST (test_upload_gl_memory)
 
 GST_END_TEST;
 
+GST_START_TEST (test_passthrough)
+{
+  guint formats_size = G_N_ELEMENTS (test_passthrough_formats);
+  guint features_size = G_N_ELEMENTS (test_passthrough_features);
+  gint i, j, k, l;
+
+  for (i = 0; i < formats_size; i++) {
+    GstVideoFormat in_format = test_passthrough_formats[i];
+
+    for (j = 0; j < formats_size; j++) {
+      GstVideoFormat out_format = test_passthrough_formats[j];
+
+      for (k = 0; k < features_size; k++) {
+        const gchar *in_feature = test_passthrough_features[k];
+        GstCaps *in_caps;
+
+        in_caps = gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING,
+            gst_video_format_to_string (in_format), NULL);
+        gst_caps_set_features_simple (in_caps,
+            gst_caps_features_from_string (in_feature));
+
+
+        for (l = 0; l < features_size; l++) {
+          const gchar *out_feature = test_passthrough_features[l];
+          GstCaps *out_caps;
+
+          out_caps = gst_caps_new_simple ("video/x-raw", "format",
+              G_TYPE_STRING, gst_video_format_to_string (out_format), NULL);
+          gst_caps_set_features_simple (out_caps,
+              gst_caps_features_from_string (out_feature));
+
+          if (gst_caps_is_equal (in_caps, out_caps)) {
+            GstCaps *tmp_caps, *tmp_caps2, *tmp_caps3;
+
+            tmp_caps = gst_gl_upload_transform_caps (upload, context,
+                GST_PAD_SINK, in_caps, NULL);
+            tmp_caps2 = gst_gl_upload_transform_caps (upload, context,
+                GST_PAD_SRC, out_caps, NULL);
+
+            tmp_caps3 = gst_caps_intersect (tmp_caps, tmp_caps2);
+
+            fail_unless (!gst_caps_is_empty (tmp_caps3));
+
+            gst_caps_unref (tmp_caps);
+            gst_caps_unref (tmp_caps2);
+            gst_caps_unref (tmp_caps3);
+          }
+
+          gst_caps_unref (out_caps);
+        }
+
+        gst_caps_unref (in_caps);
+      }
+    }
+  }
+}
+
+GST_END_TEST;
 
 static Suite *
 gst_gl_upload_suite (void)
@@ -428,6 +498,7 @@ gst_gl_upload_suite (void)
   tcase_add_checked_fixture (tc_chain, setup, teardown);
   tcase_add_test (tc_chain, test_upload_data);
   tcase_add_test (tc_chain, test_upload_gl_memory);
+  tcase_add_test (tc_chain, test_passthrough);
 
   return s;
 }