diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp
index 0b324ff5..fd07c9bd 100644
--- a/src/android/camera_device.cpp
+++ b/src/android/camera_device.cpp
@@ -240,6 +240,8 @@ CameraDevice::Camera3RequestDescriptor::Camera3RequestDescriptor(
 	/* Clone the controls associated with the camera3 request. */
 	settings_ = CameraMetadata(camera3Request->settings);
 
+	internalBuffer_ = nullptr;
+
 	/*
 	 * Create the CaptureRequest, stored as a unique_ptr<> to tie its
 	 * lifetime to the descriptor.
@@ -1002,6 +1004,7 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques
 			 * once it has been processed.
 			 */
 			buffer = cameraStream->getBuffer();
+			descriptor.internalBuffer_ = buffer;
 			LOG(HAL, Debug) << ss.str() << " (internal)";
 			break;
 		}
@@ -1161,25 +1164,115 @@ void CameraDevice::requestComplete(Request *request)
 			continue;
 		}
 
+		/*
+		 * Save the current context of capture result and queue the
+		 * descriptor before processing the camera stream.
+		 *
+		 * When the processing completes, the descriptor will be
+		 * dequeued and capture results will be sent to the framework.
+		 */
+		descriptor.status_ = Camera3RequestDescriptor::NOT_FINISHED;
+		descriptor.resultMetadata_ = std::move(resultMetadata);
+		descriptor.captureResult_ = captureResult;
+
+		std::unique_ptr<Camera3RequestDescriptor> reqDescriptor =
+			std::make_unique<Camera3RequestDescriptor>();
+		*reqDescriptor = std::move(descriptor);
+		queuedDescriptor_.push_back(std::move(reqDescriptor));
+		Camera3RequestDescriptor *currentDescriptor = queuedDescriptor_.back().get();
+
+		CameraMetadata *metadata = currentDescriptor->resultMetadata_.get();
+		cameraStream->processComplete.connect(
+			this, [=](CameraStream::ProcessStatus status) {
+				streamProcessingComplete(cameraStream, status,
+							 metadata);
+			});
+
 		int ret = cameraStream->process(src, *buffer.buffer,
-						descriptor.settings_,
-						resultMetadata.get());
+						currentDescriptor->settings_,
+						metadata);
+		return;
+	}
+
+	if (queuedDescriptor_.empty()) {
+		captureResult.result = resultMetadata->get();
+		callbacks_->process_capture_result(callbacks_, &captureResult);
+	} else {
+		/*
+		 * Previous capture results waiting to be sent to framework
+		 * hence, queue the current capture results as well. After that,
+		 * check if any results are ready to be sent back to the
+		 * framework.
+		 */
+		descriptor.status_ = Camera3RequestDescriptor::FINISHED_SUCCESS;
+		descriptor.resultMetadata_ = std::move(resultMetadata);
+		descriptor.captureResult_ = captureResult;
+		std::unique_ptr<Camera3RequestDescriptor> reqDescriptor =
+			std::make_unique<Camera3RequestDescriptor>();
+		*reqDescriptor = std::move(descriptor);
+		queuedDescriptor_.push_back(std::move(reqDescriptor));
+
+		sendQueuedCaptureResults();
+	}
+}
+
+void CameraDevice::streamProcessingComplete(CameraStream *cameraStream,
+					    CameraStream::ProcessStatus status,
+					    CameraMetadata *resultMetadata)
+{
+	for (auto &d : queuedDescriptor_) {
+		if (d->resultMetadata_.get() != resultMetadata)
+			continue;
+
 		/*
 		 * Return the FrameBuffer to the CameraStream now that we're
 		 * done processing it.
 		 */
 		if (cameraStream->type() == CameraStream::Type::Internal)
-			cameraStream->putBuffer(src);
-
-		if (ret) {
-			buffer.status = CAMERA3_BUFFER_STATUS_ERROR;
-			notifyError(descriptor.frameNumber_, buffer.stream,
-				    CAMERA3_MSG_ERROR_BUFFER);
+			cameraStream->putBuffer(d->internalBuffer_);
+
+		if (status == CameraStream::ProcessStatus::Success) {
+			d->status_ = Camera3RequestDescriptor::FINISHED_SUCCESS;
+		} else {
+			d->status_ = Camera3RequestDescriptor::FINISHED_FAILED;
+			d->captureResult_.partial_result = 0;
+			for (camera3_stream_buffer_t &buffer : d->buffers_) {
+				CameraStream *cs = static_cast<CameraStream *>(buffer.stream->priv);
+
+				if (cs->camera3Stream().format != HAL_PIXEL_FORMAT_BLOB)
+					continue;
+
+				buffer.status = CAMERA3_BUFFER_STATUS_ERROR;
+				notifyError(d->frameNumber_, buffer.stream,
+					    CAMERA3_MSG_ERROR_BUFFER);
+			}
 		}
+
+		break;
 	}
 
-	captureResult.result = resultMetadata->get();
-	callbacks_->process_capture_result(callbacks_, &captureResult);
+	/*
+	 * Send back capture results to the framework by inspecting the queue.
+	 * The framework can defer queueing further requests to the HAL (via
+	 * process_capture_request) unless until it receives the capture results
+	 * for already queued requests.
+	 */
+	sendQueuedCaptureResults();
+}
+
+void CameraDevice::sendQueuedCaptureResults()
+{
+	while (!queuedDescriptor_.empty()) {
+		std::unique_ptr<Camera3RequestDescriptor> &d = queuedDescriptor_.front();
+		if (d->status_ != Camera3RequestDescriptor::NOT_FINISHED) {
+			d->captureResult_.result = d->resultMetadata_->get();
+			callbacks_->process_capture_result(callbacks_,
+							   &(d->captureResult_));
+			queuedDescriptor_.pop_front();
+		} else {
+			break;
+		}
+	}
 }
 
 std::string CameraDevice::logPrefix() const
diff --git a/src/android/camera_device.h b/src/android/camera_device.h
index a5576927..36425773 100644
--- a/src/android/camera_device.h
+++ b/src/android/camera_device.h
@@ -7,6 +7,7 @@
 #ifndef __ANDROID_CAMERA_DEVICE_H__
 #define __ANDROID_CAMERA_DEVICE_H__
 
+#include <deque>
 #include <map>
 #include <memory>
 #include <mutex>
@@ -83,6 +84,21 @@ private:
 		std::vector<std::unique_ptr<libcamera::FrameBuffer>> frameBuffers_;
 		CameraMetadata settings_;
 		std::unique_ptr<CaptureRequest> request_;
+
+		/*
+		 * Below are utility placeholders used when a capture result
+		 * needs to be queued before completion via
+		 * process_capture_result() callback.
+		 */
+		enum completionStatus {
+			NOT_FINISHED,
+			FINISHED_SUCCESS,
+			FINISHED_FAILED,
+		};
+		std::unique_ptr<CameraMetadata> resultMetadata_;
+		camera3_capture_result_t captureResult_;
+		libcamera::FrameBuffer *internalBuffer_;
+		completionStatus status_;
 	};
 
 	enum class State {
@@ -105,6 +121,11 @@ private:
 	std::unique_ptr<CameraMetadata> getResultMetadata(
 		const Camera3RequestDescriptor &descriptor) const;
 
+	void sendQueuedCaptureResults();
+	void streamProcessingComplete(CameraStream *stream,
+				      CameraStream::ProcessStatus status,
+				      CameraMetadata *resultMetadata);
+
 	unsigned int id_;
 	camera3_device_t camera3Device_;
 
@@ -125,6 +146,8 @@ private:
 	libcamera::Mutex descriptorsMutex_; /* Protects descriptors_. */
 	std::map<uint64_t, Camera3RequestDescriptor> descriptors_;
 
+	std::deque<std::unique_ptr<Camera3RequestDescriptor>> queuedDescriptor_;
+
 	std::string maker_;
 	std::string model_;
 
