diff --git a/epicardium/modules/hardware.c b/epicardium/modules/hardware.c
index 3905ceb81811dc38c581d6ad99320c3dbadb16a5..75a995e9703456ea7ceaaa57922fc2ff4ee2c14e 100644
--- a/epicardium/modules/hardware.c
+++ b/epicardium/modules/hardware.c
@@ -150,6 +150,11 @@ int hardware_early_init(void)
 	 */
 	stream_init();
 
+	/*
+	 * Hardware/Peripheral Locks
+	 */
+	hwlock_init();
+
 	return 0;
 }
 
diff --git a/epicardium/modules/hw-lock.c b/epicardium/modules/hw-lock.c
new file mode 100644
index 0000000000000000000000000000000000000000..f02a5882b1bdb2aabddeb2ccea77d59fe14939c4
--- /dev/null
+++ b/epicardium/modules/hw-lock.c
@@ -0,0 +1,62 @@
+#include "modules/log.h"
+#include "modules/modules.h"
+
+#include "FreeRTOS.h"
+#include "task.h"
+#include "semphr.h"
+
+#include <errno.h>
+
+static StaticSemaphore_t hwlock_mutex_data[_HWLOCK_MAX];
+static SemaphoreHandle_t hwlock_mutex[_HWLOCK_MAX];
+/* Which task is holding the lock */
+static TaskHandle_t hwlock_tasks[_HWLOCK_MAX];
+
+void hwlock_init(void)
+{
+	for (int i = 0; i < _HWLOCK_MAX; i++) {
+		hwlock_mutex[i] =
+			xSemaphoreCreateMutexStatic(&hwlock_mutex_data[i]);
+	}
+}
+
+int hwlock_acquire(enum hwlock_periph p, TickType_t wait)
+{
+	if (p >= _HWLOCK_MAX) {
+		return -EINVAL;
+	}
+
+	if (xSemaphoreTake(hwlock_mutex[p], wait) != pdTRUE) {
+		LOG_WARN("hwlock", "Lock %u is busy.", p);
+		return -EBUSY;
+	}
+
+	hwlock_tasks[p] = xTaskGetCurrentTaskHandle();
+
+	return 0;
+}
+
+int hwlock_release(enum hwlock_periph p)
+{
+	int ret = 0;
+
+	if (p >= _HWLOCK_MAX) {
+		return -EINVAL;
+	}
+
+	if (hwlock_tasks[p] != xTaskGetCurrentTaskHandle()) {
+		LOG_ERR("hwlock",
+			"Lock %u is released by task \"%s\" while it was acquired by \"%s\"",
+			p,
+			pcTaskGetName(NULL),
+			pcTaskGetName(hwlock_tasks[p]));
+		ret = -EACCES;
+	}
+
+	if (xSemaphoreGive(hwlock_mutex[p]) != pdTRUE) {
+		LOG_ERR("hwlock", "Lock %u not released correctly.", p);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
diff --git a/epicardium/modules/meson.build b/epicardium/modules/meson.build
index 31e7f5c078a74f39425d70048ac0f57be28c67f5..4966be6c9122ed2333ca6a5ecf1b6fc5e5ceb988 100644
--- a/epicardium/modules/meson.build
+++ b/epicardium/modules/meson.build
@@ -5,6 +5,7 @@ module_sources = files(
   'fileops.c',
   'gpio.c',
   'hardware.c',
+  'hw-lock.c',
   'leds.c',
   'lifecycle.c',
   'light_sensor.c',
diff --git a/epicardium/modules/modules.h b/epicardium/modules/modules.h
index 535dcf5c1d87072c6ca631189ea3aec6210c2258..abf1c770939884274538b5d68e64eed36b23f896 100644
--- a/epicardium/modules/modules.h
+++ b/epicardium/modules/modules.h
@@ -37,6 +37,17 @@ void vBleTask(void *pvParameters);
 bool ble_shall_start(void);
 void ble_uart_write(uint8_t *pValue, uint8_t len);
 
+/* ---------- Hardware (Peripheral) Locks ---------------------------------- */
+void hwlock_init(void);
+
+enum hwlock_periph {
+	HWLOCK_I2C = 0,
+	_HWLOCK_MAX,
+};
+
+int hwlock_acquire(enum hwlock_periph p, TickType_t wait);
+int hwlock_release(enum hwlock_periph p);
+
 /* ---------- Display ------------------------------------------------------ */
 /* Forces an unlock of the display. Only to be used in Epicardium */
 void disp_forcelock();
diff --git a/epicardium/modules/pmic.c b/epicardium/modules/pmic.c
index 492545bb3b47c33b5494351a6f321d0af376df2c..c02691dc25350723b04bd0059183bcf0522396ae 100644
--- a/epicardium/modules/pmic.c
+++ b/epicardium/modules/pmic.c
@@ -45,7 +45,13 @@ void vPmicTask(void *pvParameters)
 			MAX77650_setSFT_RST(0x2);
 		}
 
+		while (hwlock_acquire(HWLOCK_I2C, pdMS_TO_TICKS(500)) < 0) {
+			LOG_WARN("pmic", "Failed to acquire I2C. Retrying ...");
+			vTaskDelay(pdMS_TO_TICKS(500));
+		}
+
 		uint8_t int_flag = MAX77650_getINT_GLBL();
+		hwlock_release(HWLOCK_I2C);
 
 		if (int_flag & MAX77650_INT_nEN_F) {
 			/* Button was pressed */