De Villiers, who made 91 in the first innings, was 39 not out.
As he did in the first innings, Johnson took a wicket in his first over, having Alviro Petersen caught behind for one. It was Johnson's 250th Test wicket in his 57th Test match.
South African captain Graeme Smith, who was Johnson's first over victim in the first innings, hit a four off a thick outside edge in Johnson's second over but then fell to a superb catch by Alex Doolan when he clipped the ball firmly to short leg.
Faf du Plessis was the third man out, with the total on 49, falling victim to a ball which shot through low from Peter Siddle and trapped him in front of his stumps.
Hashim Amla made a solid 35 before he was caught at first slip off Ryan Harris.
Johnson, who took seven for 68 in the first innings, completed the third ten-wicket haul of his Test career when Doolan made another outstanding catch at short leg, snapping up JP Duminy.
Johnson had figures of three for 45 at tea. Ten of the runs conceded came from two wides which flew over wicketkeeper Brad Haddin.
There was a hold-up shortly before the tea break when a Johnson bouncer hit the earpiece of Ryan McLaren's helmet, with the batsman needing treatment on the field before continuing.
Australian captain Michael Clarke declared his side's second innings closed at 290 for four after only 3.2 overs when first innings centurion Shaun Marsh was caught behind off Dale Steyn without adding to his overnight score of 44.