diff --git a/src/const.h b/src/const.h
index e6941f2cad4c62ed54f147628d47ccadab86050e..856043bf25f77e743de0daa99ea7665fc1534fe9 100644
--- a/src/const.h
+++ b/src/const.h
@@ -61,6 +61,6 @@
 /* Gravity properties */
 #define EXTERNAL_POTENTIAL_POINTMASS
 
-#define SANITY_CHECK
+#define SANITY_CHECKS
 
 #endif /* SWIFT_CONST_H */
diff --git a/src/engine.c b/src/engine.c
index dd9f6cc5910a6049f2296e58b4917f7caecfdbd0..562e1aeed642bdcac3502073e302b4e8cb2f0b5c 100644
--- a/src/engine.c
+++ b/src/engine.c
@@ -1066,6 +1066,69 @@ void engine_exchange_strays(struct engine *e, size_t offset_parts,
 #endif
 }
 
+void engine_make_gravity_tasks(struct engine *e) {
+
+  struct space *s = e->s;
+  struct scheduler *sched = &e->sched;
+  const int nodeID = e->nodeID;
+  const int *cdim = s->cdim;
+  struct cell *cells = s->cells;
+
+  message("aa");
+
+  /* Run through the highest level of cells and add pairs. */
+  for (int i = 0; i < cdim[0]; i++) {
+    for (int j = 0; j < cdim[1]; j++) {
+      for (int k = 0; k < cdim[2]; k++) {
+
+        /* Get the cell */
+        const int cid = cell_getid(cdim, i, j, k);
+        struct cell *ci = &cells[cid];
+
+        /* Skip cells without gravity particles */
+        if (ci->gcount == 0) continue;
+
+        /* If the cells is local build a self-interaction */
+        if (ci->nodeID == nodeID)
+          scheduler_addtask(sched, task_type_self, task_subtype_grav, 0, 0, ci,
+                            NULL, 0);
+
+        /* Now loop over all the neighbours of this cell */
+        for (int ii = -1; ii < 2; ii++) {
+          int iii = i + ii;
+          if (!s->periodic && (iii < 0 || iii >= cdim[0])) continue;
+          iii = (iii + cdim[0]) % cdim[0];
+          for (int jj = -1; jj < 2; jj++) {
+            int jjj = j + jj;
+            if (!s->periodic && (jjj < 0 || jjj >= cdim[1])) continue;
+            jjj = (jjj + cdim[1]) % cdim[1];
+            for (int kk = -1; kk < 2; kk++) {
+              int kkk = k + kk;
+              if (!s->periodic && (kkk < 0 || kkk >= cdim[2])) continue;
+              kkk = (kkk + cdim[2]) % cdim[2];
+
+              /* Get the neighbouring cell */
+              const int cjd = cell_getid(cdim, iii, jjj, kkk);
+              struct cell *cj = &cells[cjd];
+
+              /* Is that neighbour local and does it have particles ? */
+              if (cid >= cjd || cj->gcount == 0 ||
+                  (ci->nodeID != nodeID && cj->nodeID != nodeID))
+                continue;
+
+              /* Construct the pair task */
+              const int sid =
+                  sortlistID[(kk + 1) + 3 * ((jj + 1) + 3 * (ii + 1))];
+              scheduler_addtask(sched, task_type_pair, task_subtype_grav, sid,
+                                0, ci, cj, 1);
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
 /**
  * @brief Constructs the top-level pair tasks for the first hydro loop over
  *neighbours
@@ -1435,8 +1498,7 @@ void engine_maketasks(struct engine *e) {
   engine_make_hydroloop_tasks(e);
 
   /* Add the gravity mm tasks. */
-  /* if (e->policy & engine_policy_self_gravity) */
-  /*   engine_make_gravityinteraction_tasks(e); */
+  if (e->policy & engine_policy_self_gravity) engine_make_gravity_tasks(e);
 
   /* Split the tasks. */
   scheduler_splittasks(sched);
diff --git a/src/runner.c b/src/runner.c
index 5921691fba4c20adb136fee5513ae381761a6c71..1a094297aaa1fd66c347ae040fe43eaab4ba4e18 100644
--- a/src/runner.c
+++ b/src/runner.c
@@ -123,7 +123,6 @@ void runner_do_grav_external(struct runner *r, struct cell *c, int timer) {
     if (g->ti_end <= ti_current) {
 
       external_gravity(potential, constants, g);
-
     }
   }
   if (timer) TIMER_TOC(timer_dograv_external);
@@ -1130,14 +1129,19 @@ void *runner_main(void *data) {
             runner_doself1_density(r, ci);
           else if (t->subtype == task_subtype_force)
             runner_doself2_force(r, ci);
+          else if (t->subtype == task_subtype_grav)
+            runner_doself_grav(r, ci);
           else
             error("Unknown task subtype.");
           break;
         case task_type_pair:
+          message("bb");
           if (t->subtype == task_subtype_density)
             runner_dopair1_density(r, ci, cj);
           else if (t->subtype == task_subtype_force)
             runner_dopair2_force(r, ci, cj);
+          else if (t->subtype == task_subtype_grav)
+            runner_dopair_grav(r, ci, cj);
           else
             error("Unknown task subtype.");
           break;
diff --git a/src/runner_doiact_grav.h b/src/runner_doiact_grav.h
index 7e2293ba907ef6ae427f2b5e2ba5da156de12acf..113019a322df6ebf4c2cdefa24d44785f744c5f1 100644
--- a/src/runner_doiact_grav.h
+++ b/src/runner_doiact_grav.h
@@ -57,10 +57,10 @@ void runner_dograv_up(struct runner *r, struct cell *c) {
 /**
  * @brief Checks whether the cells are direct neighbours ot not. Both cells have
  * to be of the same size
- * 
+ *
  */
-__attribute__((always_inline)) INLINE static
-int are_neighbours(const struct cell *restrict ci, const struct cell *restrict cj) {
+__attribute__((always_inline)) INLINE static int are_neighbours(
+    const struct cell *restrict ci, const struct cell *restrict cj) {
 
 #ifdef SANITY_CHECKS
   if (ci->h[0] != cj->h[0])
@@ -80,8 +80,6 @@ int are_neighbours(const struct cell *restrict ci, const struct cell *restrict c
   return 1;
 }
 
-
-
 /**
  * @brief Computes the interaction of all the particles in a cell with the
  * multipole of another cell.
@@ -90,8 +88,9 @@ int are_neighbours(const struct cell *restrict ci, const struct cell *restrict c
  * @param ci The #cell with particles to interct.
  * @param cj The #cell with the multipole.
  */
-__attribute__((always_inline)) INLINE static void runner_dograv_pair_pm(
-	  const struct runner *r, const struct cell *restrict ci, const struct cell *restrict cj) {
+__attribute__((always_inline)) INLINE static void runner_dopair_grav_pm(
+    const struct runner *r, const struct cell *restrict ci,
+    const struct cell *restrict cj) {
 
   const struct engine *e = r->e;
   const int gcount = ci->gcount;
@@ -101,7 +100,7 @@ __attribute__((always_inline)) INLINE static void runner_dograv_pair_pm(
 
   TIMER_TIC;
 
-#ifdef SANITY_CHECK
+#ifdef SANITY_CHECKS
   if (gcount == 0) error("Empty cell!");  // MATTHIEU sanity check
 
   if (multi.mass == 0.0)  // MATTHIEU sanity check
@@ -180,7 +179,7 @@ __attribute__((always_inline)) INLINE static void runner_dograv_pair_pm(
  *
  * @todo Use a local cache for the particles.
  */
-__attribute__((always_inline)) INLINE static void runner_dograv_pair_pp(
+__attribute__((always_inline)) INLINE static void runner_dopair_grav_pp(
     struct runner *r, struct cell *ci, struct cell *cj) {
 
   const struct engine *e = r->e;
@@ -192,7 +191,7 @@ __attribute__((always_inline)) INLINE static void runner_dograv_pair_pp(
 
   TIMER_TIC;
 
-#ifdef SANITY_CHECK
+#ifdef SANITY_CHECKS
   if (ci->h[0] != cj->h[0])  // MATTHIEU sanity check
     error("Non matching cell sizes !! h_i=%f h_j=%f\n", ci->h[0], cj->h[0]);
 #endif
@@ -250,7 +249,7 @@ __attribute__((always_inline)) INLINE static void runner_dograv_pair_pp(
  * @todo Use a local cache for the particles.
  */
 __attribute__((always_inline))
-    INLINE static void runner_dograv_self_pp(struct runner *r, struct cell *c) {
+    INLINE static void runner_doself_grav_pp(struct runner *r, struct cell *c) {
 
   const struct engine *e = r->e;
   const int gcount = c->gcount;
@@ -259,7 +258,7 @@ __attribute__((always_inline))
 
   TIMER_TIC;
 
-#ifdef SANITY_CHECK
+#ifdef SANITY_CHECKS
   if (c->gcount == 0)  // MATTHIEU sanity check
     error("Empty cell !");
 #endif
@@ -308,4 +307,109 @@ __attribute__((always_inline))
   TIMER_TOC(TIMER_DOSELF);  // MATTHIEU
 }
 
+/**
+ * @brief Computes the interaction of all the particles in a cell with all the
+ * particles of another cell.
+ *
+ * @param r The #runner.
+ * @param ci The first #cell.
+ * @param cj The other #cell.
+ *
+ * @todo Use a local cache for the particles.
+ */
+static void runner_dopair_grav(struct runner *r, struct cell *ci,
+                               struct cell *cj) {
+
+  const int gcount_i = ci->gcount;
+  const int gcount_j = cj->gcount;
+
+#ifdef SANITY_CHECKS
+
+  /* Early abort? */
+  if (gcount_i == 0 || gcount_j == 0) error("Empty cell !");
+
+  /* Bad stuff will happen if cell sizes are different */
+  if (ci->h[0] != cj->h[0])
+    error("Non matching cell sizes !! h_i=%f h_j=%f\n", ci->h[0], cj->h[0]);
+
+  /* Sanity check */
+  if (ci == cj)
+    error(
+        "The impossible has happened: pair interaction between a cell and "
+        "itself.");
+
+  /* Are the cells direct neighbours? */
+  if (!are_neighbours(ci, cj)) error("Non-neighbouring cells !");
+
+#endif
+
+  /* Are both cells split ? */
+  if (ci->split && cj->split) {
+
+    for (int j = 0; j < 8; j++) {
+      if (ci->progeny[j] != NULL) {
+
+        for (int k = 0; k < 8; k++) {
+          if (cj->progeny[k] != NULL) {
+
+            if (are_neighbours(ci->progeny[j], cj->progeny[k])) {
+
+              /* Recurse */
+              runner_dopair_grav(r, ci->progeny[j], cj->progeny[k]);
+
+            } else {
+
+              /* Ok, here we can go for particle-multipole interactions */
+              runner_dopair_grav_pm(r, ci->progeny[j], cj->progeny[k]);
+              runner_dopair_grav_pm(r, cj->progeny[k], ci->progeny[j]);
+            }
+          }
+        }
+      }
+    }
+  } else {/* Not split */
+
+    /* Compute the interactions at this level directly. */
+    runner_dopair_grav_pp(r, ci, cj);
+  }
+}
+
+static void runner_doself_grav(struct runner *r, struct cell *c) {
+
+  const int gcount = c->gcount;
+
+#ifdef SANITY_CHECKS
+
+  /* Early abort? */
+  if (gcount == 0) error("Empty cell !");
+#endif
+
+  message("aa");
+
+  /* If the cell is split, interact each progeny with itself, and with
+     each of its siblings. */
+  if (c->split) {
+
+    for (int j = 0; j < 8; j++) {
+      if (c->progeny[j] != NULL) {
+
+        runner_doself_grav(r, c->progeny[j]);
+
+        for (int k = j + 1; k < 8; k++) {
+          if (c->progeny[k] != NULL) {
+
+            runner_dopair_grav(r, c->progeny[j], c->progeny[k]);
+          }
+        }
+      }
+    }
+  }
+
+  /* If the cell is not split, then just go for it... */
+  else {
+
+    runner_doself_grav_pp(r, c);
+  }
+}
+
 #endif /* SWIFT_RUNNER_DOIACT_GRAV_H */
diff --git a/src/scheduler.c b/src/scheduler.c
index 887e8d54fd1fda941fe0024c45733226ce8d4b43..539b36892adfc2a65d9d0c9954f06a2817eda9df 100644
--- a/src/scheduler.c
+++ b/src/scheduler.c
@@ -172,7 +172,8 @@ void scheduler_splittasks(struct scheduler *s) {
       if (ci->split) {
 
         /* Make a sub? */
-        if (scheduler_dosub && ci->count < space_subsize / ci->count) {
+        if (scheduler_dosub && (ci->count * ci->count < space_subsize ||
+                                ci->gcount * ci->gcount < space_subsize)) {
 
           /* convert to a self-subtask. */
           t->type = task_type_sub;
@@ -233,7 +234,8 @@ void scheduler_splittasks(struct scheduler *s) {
 
         /* Replace by a single sub-task? */
         if (scheduler_dosub &&
-            ci->count * sid_scale[sid] < space_subsize / cj->count &&
+            (ci->count * cj->count * sid_scale[sid] < space_subsize ||
+             ci->gcount * cj->gcount * sid_scale[sid] < space_subsize) &&
             sid != 0 && sid != 2 && sid != 6 && sid != 8) {
 
           /* Make this task a sub task. */