diff --git a/include/libcamera/allocator.h b/include/libcamera/allocator.h
new file mode 100644
index 0000000000000000..36fce38491b5f3ef
--- /dev/null
+++ b/include/libcamera/allocator.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2019, Google Inc.
+ *
+ * allocator.h - Buffer allocator
+ */
+#ifndef __LIBCAMERA_ALLOCATOR_H__
+#define __LIBCAMERA_ALLOCATOR_H__
+
+#include <map>
+#include <memory>
+#include <vector>
+
+namespace libcamera {
+
+class Camera;
+class FrameBuffer;
+class Stream;
+struct StreamConfiguration;
+
+class BufferAllocator
+{
+public:
+	BufferAllocator(std::shared_ptr<Camera> camera);
+	~BufferAllocator();
+
+	int allocate(Stream *stream, const StreamConfiguration &config);
+	void release(Stream *stream);
+
+	const std::vector<FrameBuffer *> &buffers(Stream *stream) const;
+
+private:
+	std::shared_ptr<Camera> camera_;
+	std::map<Stream *, std::vector<FrameBuffer *>> buffers_;
+};
+
+} /* namespace libcamera */
+
+#endif /* __LIBCAMERA_ALLOCATOR_H__ */
diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build
index 99abf06099407c1f..0d0ba2248fd8a679 100644
--- a/include/libcamera/meson.build
+++ b/include/libcamera/meson.build
@@ -1,4 +1,5 @@
 libcamera_api = files([
+    'allocator.h',
     'bound_method.h',
     'buffer.h',
     'camera.h',
diff --git a/include/libcamera/stream.h b/include/libcamera/stream.h
index a3c692c347340382..8e653408fd54cf74 100644
--- a/include/libcamera/stream.h
+++ b/include/libcamera/stream.h
@@ -85,6 +85,7 @@ public:
 	MemoryType memoryType() const { return memoryType_; }
 
 protected:
+	friend class BufferAllocator; /* To allocate and release buffers. */
 	friend class Camera;
 
 	virtual int allocateBuffers(const StreamConfiguration &config,
diff --git a/src/libcamera/allocator.cpp b/src/libcamera/allocator.cpp
new file mode 100644
index 0000000000000000..8b517c809c05cbcd
--- /dev/null
+++ b/src/libcamera/allocator.cpp
@@ -0,0 +1,141 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2019, Google Inc.
+ *
+ * allocator.cpp - Buffer allocator
+ */
+
+#include <libcamera/allocator.h>
+
+#include <errno.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <libcamera/camera.h>
+#include <libcamera/stream.h>
+
+#include "log.h"
+
+/**
+ * \file allocator.h
+ * \brief Buffer allocator
+ */
+
+namespace libcamera {
+
+LOG_DEFINE_CATEGORY(Allocator)
+
+/**
+ * \class BufferAllocator
+ * \brief Buffer allocator for applications
+ *
+ * All buffers are to be treated as if they where allocated outside of the
+ * camera. In some situations however the only source applications can allocate
+ * buffers from is the camera. The BufferAllocator is the interface applications
+ * shall use in these situations.
+ *
+ * The buffer allocator creates buffers using resources from a camera and/or
+ * a stream. The buffers allocated this way are owned by the application and it
+ * is responsible for their lifetime management. But just as buffers allocated
+ * external from cameras and streams it's not valid to free a buffer while it's
+ * queue to a camera.
+ *
+ * All buffers allocator are automatically freed when the allocator object is
+ * deleted. It is the applications responsibility to make sure this do not
+ * happen while one or more of the buffers are queued to a camera.
+ *
+ * If buffers are allocated outside the scope of libcamera by the application it
+ * do not need to interact with the buffer allocator.
+ */
+
+/**
+ * \brief Create a BufferAllocator serving a camera
+ * \param[in] camera Camera the allocator shall serve
+ */
+
+BufferAllocator::BufferAllocator(std::shared_ptr<Camera> camera)
+	: camera_(camera)
+{
+}
+
+BufferAllocator::~BufferAllocator()
+{
+	for (auto &value : buffers_) {
+		Stream *stream = value.first;
+		std::vector<FrameBuffer *> &buffers = value.second;
+
+		for (FrameBuffer *buffer : buffers)
+			delete buffer;
+
+		buffers.clear();
+
+		stream->releaseBuffers();
+	}
+
+	buffers_.clear();
+}
+
+/**
+ * \brief Allocate buffers from a stream
+ * \param[in] stream The stream to allocate buffers from
+ * \param[in] config The configuration described the buffers to be allocated
+ *
+ * Allocate buffers matching exactly what is described in \a config. If buffers
+ * matching \a config can't be allocated an error is returned and no buffers are
+ * allocated.
+ *
+ * \return 0 on success or a negative error code otherwise
+ */
+int BufferAllocator::allocate(Stream *stream, const StreamConfiguration &config)
+{
+	auto iter = camera_->streams().find(stream);
+	if (iter != camera_->streams().end())
+		return stream->allocateBuffers(config, &buffers_[stream]);
+
+	LOG(Allocator, Error) << "Stream do not belong to " << camera_->name();
+	return -EINVAL;
+}
+
+/**
+ * \brief Free allocated buffers
+ * \param[in] stream The stream to free buffers for
+ *
+ * Free buffers allocated with allocate().
+ */
+void BufferAllocator::release(Stream *stream)
+{
+	auto iter = buffers_.find(stream);
+	if (iter == buffers_.end())
+		return;
+
+	std::vector<FrameBuffer *> &buffers = iter->second;
+
+	for (FrameBuffer *buffer : buffers)
+		delete buffer;
+
+	buffers.clear();
+
+	stream->releaseBuffers();
+
+	buffers_.erase(iter);
+}
+
+/**
+ * \brief Retrive array of allocated buffers
+ * \param[in] stream The stream to retrive buffers for
+ *
+ * \return Array of buffers
+ */
+const std::vector<FrameBuffer *> &BufferAllocator::buffers(Stream *stream) const
+{
+	static std::vector<FrameBuffer *> empty;
+
+	auto iter = buffers_.find(stream);
+	if (iter == buffers_.end())
+		return empty;
+
+	return iter->second;
+}
+
+} /* namespace libcamera */
diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
index c4f965bd7413b37e..b7041e003fdb1d49 100644
--- a/src/libcamera/meson.build
+++ b/src/libcamera/meson.build
@@ -1,4 +1,5 @@
 libcamera_sources = files([
+    'allocator.cpp',
     'bound_method.cpp',
     'buffer.cpp',
     'byte_stream_buffer.cpp',
