diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c
index c575198e8354..30e04ed2e3a5 100644
--- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
+++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
@@ -83,10 +83,11 @@ static int __verify_planes_array(struct vb2_buffer *vb, const struct v4l2_buffer
 	return 0;
 }
 
-static int __verify_planes_array_core(struct vb2_buffer *vb, const void *pb)
+int vb2_buf_verify_planes_array(struct vb2_buffer *vb, const void *pb)
 {
 	return __verify_planes_array(vb, pb);
 }
+EXPORT_SYMBOL_GPL(vb2_buf_verify_planes_array);
 
 /*
  * __verify_length() - Verify that the bytesused value for each plane fits in
@@ -129,16 +130,17 @@ static int __verify_length(struct vb2_buffer *vb, const struct v4l2_buffer *b)
 }
 
 /*
- * __init_vb2_v4l2_buffer() - initialize the vb2_v4l2_buffer struct
+ * vb2_buf_init_buffer() - initialize the vb2_v4l2_buffer struct
  */
-static void __init_vb2_v4l2_buffer(struct vb2_buffer *vb)
+void vb2_buf_init_buffer(struct vb2_buffer *vb)
 {
 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
 
 	vbuf->request_fd = -1;
 }
+EXPORT_SYMBOL_GPL(vb2_buf_init_buffer);
 
-static void __copy_timestamp(struct vb2_buffer *vb, const void *pb)
+void vb2_buf_copy_timestamp(struct vb2_buffer *vb, const void *pb)
 {
 	const struct v4l2_buffer *b = pb;
 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
@@ -156,6 +158,7 @@ static void __copy_timestamp(struct vb2_buffer *vb, const void *pb)
 			vbuf->timecode = b->timecode;
 	}
 };
+EXPORT_SYMBOL_GPL(vb2_buf_copy_timestamp);
 
 static void vb2_warn_zero_bytesused(struct vb2_buffer *vb)
 {
@@ -473,10 +476,10 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md
 }
 
 /*
- * __fill_v4l2_buffer() - fill in a struct v4l2_buffer with information to be
+ * vb2_buf_fill_v4l2_buffer() - fill in a struct v4l2_buffer with information to be
  * returned to userspace
  */
-static void __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb)
+void vb2_buf_fill_v4l2_buffer(struct vb2_buffer *vb, void *pb)
 {
 	struct v4l2_buffer *b = pb;
 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
@@ -579,13 +582,14 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb)
 		b->request_fd = vbuf->request_fd;
 	}
 }
+EXPORT_SYMBOL_GPL(vb2_buf_fill_v4l2_buffer);
 
 /*
- * __fill_vb2_buffer() - fill a vb2_buffer with information provided in a
+ * vb2_buf_fill_vb2_buffer() - fill a vb2_buffer with information provided in a
  * v4l2_buffer by the userspace. It also verifies that struct
  * v4l2_buffer has a valid number of planes.
  */
-static int __fill_vb2_buffer(struct vb2_buffer *vb, struct vb2_plane *planes)
+int vb2_buf_fill_vb2_buffer(struct vb2_buffer *vb, struct vb2_plane *planes)
 {
 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
 	unsigned int plane;
@@ -603,13 +607,14 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, struct vb2_plane *planes)
 	}
 	return 0;
 }
+EXPORT_SYMBOL_GPL(vb2_buf_fill_vb2_buffer);
 
 static const struct vb2_buf_ops v4l2_buf_ops = {
-	.verify_planes_array	= __verify_planes_array_core,
-	.init_buffer		= __init_vb2_v4l2_buffer,
-	.fill_user_buffer	= __fill_v4l2_buffer,
-	.fill_vb2_buffer	= __fill_vb2_buffer,
-	.copy_timestamp		= __copy_timestamp,
+	.verify_planes_array	= vb2_buf_verify_planes_array,
+	.init_buffer		= vb2_buf_init_buffer,
+	.fill_user_buffer	= vb2_buf_fill_v4l2_buffer,
+	.fill_vb2_buffer	= vb2_buf_fill_vb2_buffer,
+	.copy_timestamp		= vb2_buf_copy_timestamp,
 };
 
 struct vb2_buffer *vb2_find_buffer(struct vb2_queue *q, u64 timestamp)
@@ -921,7 +926,8 @@ int vb2_queue_init_name(struct vb2_queue *q, const char *name)
 	if (q->buf_struct_size == 0)
 		q->buf_struct_size = sizeof(struct vb2_v4l2_buffer);
 
-	q->buf_ops = &v4l2_buf_ops;
+	if (!q->buf_ops)
+		q->buf_ops = &v4l2_buf_ops;
 	q->is_multiplanar = V4L2_TYPE_IS_MULTIPLANAR(q->type);
 	q->is_output = V4L2_TYPE_IS_OUTPUT(q->type);
 	q->copy_timestamp = (q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK)
diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
index 8b86996b2719..6f8df9acf6a2 100644
--- a/include/media/videobuf2-core.h
+++ b/include/media/videobuf2-core.h
@@ -455,6 +455,13 @@ struct vb2_ops {
 /**
  * struct vb2_buf_ops - driver-specific callbacks.
  *
+ * These operations are called by the videobuf2 framework unconditionally.
+ * Drivers are allowed to override some of the operations but shall:
+ *
+ * a) Populate all the members of this structure
+ * b) Call the generic core helper as part of their own implementations (see
+ *    vb2_buf_* helpers in videobuf2-v4l2.h)
+ *
  * @verify_planes_array: Verify that a given user space structure contains
  *			enough planes for the buffer. This is called
  *			for each dequeued buffer.
diff --git a/include/media/videobuf2-v4l2.h b/include/media/videobuf2-v4l2.h
index 5a845887850b..7c6cea933e28 100644
--- a/include/media/videobuf2-v4l2.h
+++ b/include/media/videobuf2-v4l2.h
@@ -383,6 +383,14 @@ void vb2_ops_wait_prepare(struct vb2_queue *vq);
  */
 void vb2_ops_wait_finish(struct vb2_queue *vq);
 
+/* struct vb2_buf_ops helpers */
+
+int vb2_buf_verify_planes_array(struct vb2_buffer *vb, const void *pb);
+void vb2_buf_init_buffer(struct vb2_buffer *vb);
+void vb2_buf_fill_v4l2_buffer(struct vb2_buffer *vb, void *pb);
+int vb2_buf_fill_vb2_buffer(struct vb2_buffer *vb, struct vb2_plane *planes);
+void vb2_buf_copy_timestamp(struct vb2_buffer *vb, const void *pb);
+
 struct media_request;
 int vb2_request_validate(struct media_request *req);
 void vb2_request_queue(struct media_request *req);
